bitkeeper revision 1.999.1.1 (40d8915c_Ar85TqYtbqEdZrkpMNL_A)
authormjw@wray-m-3.hpl.hp.com <mjw@wray-m-3.hpl.hp.com>
Tue, 22 Jun 2004 20:06:52 +0000 (20:06 +0000)
committermjw@wray-m-3.hpl.hp.com <mjw@wray-m-3.hpl.hp.com>
Tue, 22 Jun 2004 20:06:52 +0000 (20:06 +0000)
Move interface bridging out of xenlinux kernel into xend.

.rootkeys
linux-2.4.26-xen-sparse/arch/xen/drivers/netif/backend/interface.c
tools/xenmgr/lib/XendBridge.py [new file with mode: 0644]
tools/xenmgr/lib/XendDomain.py
tools/xenmgr/lib/XendDomainInfo.py
tools/xenmgr/lib/server/SrvConsoleServer.py
tools/xenmgr/lib/server/SrvServer.py
tools/xenmgr/lib/server/blkif.py
tools/xenmgr/lib/server/netif.py
tools/xenmgr/netfix

index fe4c4ae455929ce89f711fd01d526d8be6b965f3..acbd6201cb8d6b9e8c0bc88f3ecf8199269972b1 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 40c9c468Um_qc66OQeLEceIz1pgD5g tools/xenmgr/lib/EventServer.py
 40c9c468U8EVl0d3G--8YXVg6VJD3g tools/xenmgr/lib/EventTypes.py
 40c9c468QJTEuk9g4qHxGpmIi70PEQ tools/xenmgr/lib/PrettyPrint.py
+40d8915cyoVA0hJxiBFNymL7YvDaRg tools/xenmgr/lib/XendBridge.py
 40c9c4688m3eqnC8fhLu1APm36VOVA tools/xenmgr/lib/XendClient.py
 40c9c468t6iIKTjwuYoe-UMCikDcOQ tools/xenmgr/lib/XendConsole.py
 40c9c468WnXs6eOUSff23IIGI4kMfQ tools/xenmgr/lib/XendDB.py
index 09b4a1f0f0ef347d9c214d513ea698af13ce410e..cc20e780cee2d811f8b585a50368e65d00bf9a06 100644 (file)
 #define NETIF_HASH(_d,_h) (((int)(_d)^(int)(_h))&(NETIF_HASHSZ-1))
 
 static netif_t *netif_hash[NETIF_HASHSZ];
+#ifdef XEN_BRIDGE
 static struct net_device *bridge_dev;
 static struct net_bridge *bridge_br;
+#endif
 
 netif_t *netif_find_by_handle(domid_t domid, unsigned int handle)
 {
@@ -38,7 +40,9 @@ void __netif_disconnect_complete(netif_t *netif)
     unbind_evtchn_from_irq(netif->evtchn);
     vfree(netif->tx); /* Frees netif->rx as well. */
     rtnl_lock();
+#ifdef XEN_BRIDGE
     (void)br_del_if(bridge_br, netif->dev);
+#endif
     (void)dev_close(netif->dev);
     rtnl_unlock();
 
@@ -240,6 +244,7 @@ void netif_connect(netif_be_connect_t *connect)
     rtnl_lock();
 
     (void)dev_open(netif->dev);
+#ifdef XEN_BRIDGE
     (void)br_add_if(bridge_br, netif->dev);
 
     /*
@@ -254,6 +259,7 @@ void netif_connect(netif_be_connect_t *connect)
         (void)dev_open(eth0_dev);
         (void)br_add_if(bridge_br, eth0_dev);
     }
+#endif
 
     rtnl_unlock();
 
@@ -295,6 +301,7 @@ int netif_disconnect(netif_be_disconnect_t *disconnect, u8 rsp_id)
 void netif_interface_init(void)
 {
     memset(netif_hash, 0, sizeof(netif_hash));
+#ifdef XEN_BRIDGE
     if ( br_add_bridge("nbe-br") != 0 )
         BUG();
     bridge_dev = __dev_get_by_name("nbe-br");
@@ -302,14 +309,17 @@ void netif_interface_init(void)
     bridge_br->bridge_hello_time = bridge_br->hello_time = 0;
     bridge_br->bridge_forward_delay = bridge_br->forward_delay = 0;
     bridge_br->stp_enabled = 0;
+#endif
 }
 
 #ifndef CONFIG_BRIDGE
 #error Must configure Ethernet bridging in Network Options
 #endif
+#ifndef XEN_BRIDGE
 EXPORT_SYMBOL(br_add_bridge);
 EXPORT_SYMBOL(br_del_bridge);
 EXPORT_SYMBOL(br_add_if);
 EXPORT_SYMBOL(br_del_if);
 EXPORT_SYMBOL(br_get_bridge_ifindices);
 EXPORT_SYMBOL(br_get_port_ifindices);
+#endif
diff --git a/tools/xenmgr/lib/XendBridge.py b/tools/xenmgr/lib/XendBridge.py
new file mode 100644 (file)
index 0000000..1be8024
--- /dev/null
@@ -0,0 +1,182 @@
+"""Bridge control utilities.
+"""
+import os
+import os.path
+import re
+import sys
+
+from xenmgr import XendRoot
+xroot = XendRoot.instance()
+
+os.defpath = os.defpath + ':/sbin:/usr/sbin:/usr/local/sbin'
+CMD_IFCONFIG = 'ifconfig'
+CMD_ROUTE    = 'route'
+CMD_BRCTL    = 'brctl'
+
+DEFAULT_BRIDGE = 'nbe-br'
+DEFAULT_INTERFACE = 'eth0'
+
+opts = None
+
+class Opts:
+
+    def __init__(self, defaults):
+        for (k, v) in defaults.items():
+            setattr(self, k, v)
+        pass
+
+def cmd(p, s):
+    """Print and execute command 'p' with args 's'.
+    """
+    global opts
+    c = p + ' ' + s
+    if opts.verbose: print c
+    if not opts.dryrun:
+        os.system(c)
+
+def default_bridge():
+    return xroot.get_config_value('bridge', DEFAULT_BRIDGE)
+
+def default_interface():
+    return xroot.get_config_value('interface', DEFAULT_INTERFACE)
+
+def vif_dev(dom, vif):
+    """Return the name of the network interface for vif on domain dom.
+    """
+    return "vif%d.%d" % (dom, vif)
+
+def vif_bridge_add(dom, vif, bridge=None):
+    """Add the network interface for vif on dom to a bridge.
+    """
+    if not bridge: bridge = default_bridge()
+    d = { 'bridge': bridge, 'vif': vif_dev(dom, vif) }
+    cmd(CMD_BRCTL, 'addif %(bridge)s %(vif)s' % d)
+    return bridge
+
+def vif_bridge_rem(dom, vif, bridge=None):
+    """Remove the network interface for vif on dom from a bridge.
+    """
+    if not bridge: bridge = default_bridge()
+    print 'vif_bridge_rem>', dom, vif, bridge
+    d = { 'bridge': bridge, 'vif': vif_dev(dom, vif) }
+    cmd(CMD_BRCTL, 'delif %(bridge)s %(vif)s' % d)
+
+def bridge_create(bridge=None, **kwd):
+    """Create a bridge.
+    Defaults hello time to 0, forward delay to 0 and stp off.
+    """
+    if not bridge: bridge = default_bridge()
+    cmd(CMD_BRCTL, 'addbr %s' % bridge)
+    if kwd.get('hello', None) is None:
+        kwd['hello'] = 0
+    if kwd.get('fd', None) is None:
+        kwd['fd'] = 0
+    if kwd.get('stp', None) is None:
+        kwd['stp'] = 'off'
+    bridge_set(bridge, **kwd)
+
+def bridge_set(bridge, hello=None, fd=None, stp=None):
+    """Set bridge parameters.
+    """
+    if hello is not None:
+        cmd(CMD_BRCTL, 'sethello %s %d' % (bridge, hello))
+    if fd is not None:
+        cmd(CMD_BRCTL, 'setfd %s %d' % (bridge, fd))
+    if stp is not None:
+        cmd(CMD_BRCTL, 'stp %s %s' % (bridge, stp))
+
+def bridge_del(bridge=None):
+    """Delete a bridge.
+    """
+    if not bridge: bridge = default_bridge()
+    cmd(CMD_BRCTL, 'delbr %s' % bridge)
+
+def routes():
+    """Return a list of the routes.
+    """
+    fin = os.popen(CMD_ROUTE + ' -n', 'r')
+    routes = []
+    for x in fin:
+        if x.startswith('Kernel'): continue
+        if x.startswith('Destination'): continue
+        x = x.strip()
+        y = x.split()
+        z = { 'destination': y[0],
+              'gateway'    : y[1],
+              'mask'       : y[2],
+              'flags'      : y[3],
+              'metric'     : y[4],
+              'ref'        : y[5],
+              'use'        : y[6],
+              'interface'  : y[7] }
+        routes.append(z)
+    return routes
+
+def ifconfig(interface):
+    """Return the ip config for an interface,
+    """
+    fin = os.popen(CMD_IFCONFIG + ' %s' % interface, 'r')
+    inetre = re.compile('\s*inet\s*addr:(?P<address>\S*)\s*Bcast:(?P<broadcast>\S*)\s*Mask:(?P<mask>\S*)')
+    info = None
+    for x in fin:
+        m = inetre.match(x)
+        if not m: continue
+        info = m.groupdict()
+        info['interface'] = interface
+        break
+    return info
+
+def reconfigure(interface=None, bridge=None):
+    """Reconfigure an interface to be attached to a bridge, and give the bridge
+    the IP address etc. from interface. Move the default route to the interface
+    to the bridge.
+
+    If opts.create is true, creates the bridge.
+    """
+    global opts
+    if not interface: interface = default_interface()
+    if not bridge: bridge = default_bridge()
+    intf_info = ifconfig(interface)
+    if not intf_info:
+        print 'Interface not found:', interface
+        return
+    if opts.create:
+        bridge_create(bridge)
+    #bridge_info = ifconfig(bridge)
+    #if not bridge_info:
+    #    print 'Bridge not found:', bridge
+    #    return
+    route_info = routes()
+    intf_info['bridge'] = bridge
+    intf_info['gateway'] = None
+    for r in route_info:
+        if (r['destination'] == '0.0.0.0' and
+            'G' in r['flags'] and
+            r['interface'] == interface):
+            intf_info['gateway'] = r['gateway']
+    if not intf_info['gateway']:
+        print 'Gateway not found: ', interface
+        return
+    cmd(CMD_IFCONFIG,
+        '%(bridge)s %(address)s netmask %(mask)s broadcast %(broadcast)s up'
+        % intf_info)
+    cmd(CMD_ROUTE,
+        'add default gateway %(gateway)s dev %(bridge)s'
+        % intf_info)
+    cmd(CMD_BRCTL, 'addif %(bridge)s %(interface)s' % intf_info)
+    cmd(CMD_IFCONFIG, '%(interface)s 0.0.0.0' % intf_info)
+
+defaults = {
+    'interface': default_interface(),
+    'bridge'   : default_bridge(),
+    'verbose'  : 1,
+    'dryrun'   : 0,
+    'create'   : 0,
+    }
+
+opts = Opts(defaults)
+
+def set_opts(val):
+    global opts
+    opts = val
+    return opts
index d3cddc4e7582d0177e3fe1eb5285a611d8c9cbe3..f236a43d8094fe67b2642d62b15a1a142c7c7b3b 100644 (file)
@@ -8,7 +8,6 @@ import sys
 
 import Xc; xc = Xc.new()
 import xenctl.ip
-import xenctl.vdisk
 
 import sxp
 import XendRoot
@@ -125,6 +124,7 @@ class XendDomain:
 
     def _delete_domain(self, id, notify=1):
         if id in self.domain:
+            self.domain[id].died()
             if notify: eserver.inject('xend.domain.died', id)
             del self.domain[id]
         if id in self.domain_db:
index 88598cd9c62299e3337a8e599441ccd584e582c1..182b523d1152624b409ca7b56a3e07c3b4864700 100644 (file)
@@ -17,7 +17,6 @@ import os
 from twisted.internet import defer
 
 import Xc; xc = Xc.new()
-
 import xenctl.ip
 
 import sxp
@@ -25,6 +24,8 @@ import sxp
 import XendConsole
 xendConsole = XendConsole.instance()
 
+import XendBridge
+
 import server.SrvConsoleServer
 xend = server.SrvConsoleServer.instance()
 
@@ -183,6 +184,18 @@ class XendDomainInfo:
             return 0
         return xc.domain_destroy(dom=self.dom)
 
+    def died(self):
+        print 'died>', self.dom
+        self.release_vifs()
+
+    def release_vifs(self):
+        print 'release_vifs>', self.dom
+        vifs = self.get_devices('vif')
+        for v in vifs:
+            vif = sxp.child_value(v, 'vif')
+            bridge = sxp.child_value(v, 'bridge')
+            XendBridge.vif_bridge_rem(self.dom, vif, bridge)
+
     def show(self):
         """Print virtual machine info.
         """
@@ -264,7 +277,7 @@ def lookup_disk_uname( uname ):
         segments = None
     return segments
 
-def make_disk(dom, uname, dev, mode, sharing):
+def make_disk(dom, uname, dev, mode):
     """Create a virtual disk device for a domain.
 
     @returns Deferred
@@ -689,10 +702,14 @@ def vm_dev_vif(vm, val, index):
         raise VmError('vif: vif in control domain')
     vif = index #todo
     vmac = sxp.child_value(val, "mac")
-    bridge = sxp.child_value(val, "bridge") # todo
     defer = make_vif(vm.dom, vif, vmac)
     def fn(id):
-        dev = val + ['vif', vif]
+        bridge = sxp.child_value(val, "bridge")
+        bridge = XendBridge.vif_bridge_add(vm.dom, vif, bridge)
+        dev = ['vif', ['vif', vif], ['bridge', bridge] ]
+        netdev = xend.netif_dev(vm.dom, vif)
+        if netdev and netdev.mac:
+            dev += [ 'mac', netdev.mac ]
         vm.add_device('vif', dev)
         print 'vm_dev_vif> created', dev
         return id
@@ -715,8 +732,7 @@ def vm_dev_vbd(vm, val, index):
     if not dev:
         raise VMError('vbd: Missing dev')
     mode = sxp.child_value(val, 'mode', 'r')
-    sharing = sxp.child_value(val, 'sharing', 'rr')
-    defer = make_disk(vm.dom, uname, dev, mode, sharing)
+    defer = make_disk(vm.dom, uname, dev, mode)
     def fn(vbd):
         vm.add_device('vbd', val)
         return vbd
index 21d39140b25b35be84476c0c37a1dc49aec96605..7179a0d1d47b0da43af27df9246e566cbee98f62 100644 (file)
@@ -549,7 +549,7 @@ class Daemon:
         self.listenEvent()
         self.listenNotifier()
         self.listenVirq()
-        SrvServer.create()
+        SrvServer.create(bridge=1)
         reactor.run()
 
     def createFactories(self):
@@ -602,6 +602,9 @@ class Daemon:
         d = self.blkifCF.createInstance(dom)
         return d
 
+    def blkif_dev(self, dom, vdev):
+        return self.blkifCF.getDomainDevice(dom, vdev)
+
     def blkif_dev_create(self, dom, vdev, mode, segment):
         """Create a block device.
         
@@ -641,6 +644,9 @@ class Daemon:
         d = ctrl.attach_device(vif, vmac)
         return d
 
+    def netif_dev(self, dom, vif):
+        return self.netifCF.getDomainDevice(dom, vif)
+
     def console_create(self, dom, console_port=None):
         """Create a console for a domain.
         """
index a42219b6206f93a1316f022dc2c14d02630ad1d9..d507c2002bc37195299972728666478f1f8749ef 100644 (file)
@@ -32,17 +32,24 @@ from twisted.internet import reactor
 from xenmgr import XendRoot
 xroot = XendRoot.instance()
 
+from xenmgr import XendBridge
+
 from SrvRoot import SrvRoot
 
-def create(port=None, interface=None):
+def create(port=None, interface=None, bridge=0):
     if port is None: port = 8000
     if interface is None: interface = ''
+    if bridge or xroot.rebooted:
+        init_bridge()
     root = resource.Resource()
     xend = SrvRoot()
     root.putChild('xend', xend)
     site = server.Site(root)
     reactor.listenTCP(port, site, interface=interface)
-    
+
+def init_bridge():
+    XendBridge.bridge_create()
+    XendBridge.reconfigure()
 
 def main(port=None, interface=None):
     create(port, interface)
index 7ffa35179d7ad4b454f1f4c65832bbc55a7503d4..8da827baa9d65ed9401cf66bee6f4b56bf8cef11 100755 (executable)
@@ -33,6 +33,14 @@ class BlkifControllerFactory(controller.ControllerFactory):
             blkif.send_be_create()
         return d
 
+    def getDomainDevices(self, dom):
+        blkif = self.getInstanceByDom(dom)
+        return (blkif and blkif.getDevices()) or []
+
+    def getDomainDevice(self, dom, vdev):
+        blkif = self.getInstanceByDom(dom)
+        return (blkif and blkif.getDevice(vdev)) or None
+
     def setControlDomain(self, dom):
         if self.dom == dom: return
         self.deregisterChannel()
@@ -146,6 +154,12 @@ class BlkifController(controller.Controller):
         self.registerChannel()
         #print 'BlkifController<', 'dom=', self.dom, 'idx=', self.idx
 
+    def getDevices(self):
+        return self.devices.values()
+
+    def getDevice(self, vdev):
+        return self.devices.get(vdev)
+
     def attach_device(self, vdev, mode, segment):
         """Attach a device to the specified interface.
         """
index 13bdd96486940ce552e05ec3182bff704eae378a..f3da86ba824691bc8f84a42123d319be9a2d78e7 100755 (executable)
@@ -31,6 +31,14 @@ class NetifControllerFactory(controller.ControllerFactory):
             netif = NetifController(self, dom)
             self.addInstance(netif)
         return netif
+
+    def getDomainDevices(self, dom):
+        netif = self.getInstanceByDom(dom)
+        return (netif and netif.getDevices()) or []
+
+    def getDomainDevice(self, dom, vif):
+        netif = self.getInstanceByDom(dom)
+        return (netif and netif.getDevice(vif)) or None
         
     def setControlDomain(self, dom):
         """Set the 'back-end' device driver domain.
@@ -98,6 +106,11 @@ class NetDev:
         self.vif = vif
         self.mac = mac
         self.evtchn = None
+
+    def sxpr(self):
+        vif = str(self.vif)
+        mac = ':'.join(map(lambda x: "%x" % x, self.mac))
+        return ['netif', ['vif', vif], ['mac', mac]]
     
 class NetifController(controller.Controller):
     """Network interface controller. Handles all network devices for a domain.
@@ -135,20 +148,37 @@ class NetifController(controller.Controller):
                 random.randint(0x00, 0xff) ]
         return mac
 
-    def attach_device(self, vif, vmac):
-        """Attach a network device.
-        If vmac is None a random mac address is assigned.
+    def lostChannel(self):
+        print 'NetifController>lostChannel>', 'dom=', self.dom
+        #for vif in self.devices:
+        #    self.send_be_destroy(vif)
+        controller.Controller.lostChannel(self)
 
-        @param vif interface index
-        @param vmac mac address (string)
-        """
+    def getDevices(self):
+        return self.devices.values()
+
+    def getDevice(self, vif):
+        return self.devices.get(vif)
+
+    def addDevice(self, vif, vmac):
         if vmac is None:
             mac = self.randomMAC()
         else:
             mac = [ int(x, 16) for x in vmac.split(':') ]
         if len(mac) != 6: raise ValueError("invalid mac")
         #print "attach_device>", "vif=", vif, "mac=", mac
-        self.devices[vif] = NetDev(vif, mac)
+        dev = NetDev(vif, mac)
+        self.devices[vif] = dev
+        return dev
+
+    def attach_device(self, vif, vmac):
+        """Attach a network device.
+        If vmac is None a random mac address is assigned.
+
+        @param vif interface index
+        @param vmac mac address (string)
+        """
+        self.addDevice(vif, vmac)
         d = self.factory.addDeferred()
         self.send_be_create(vif)
         return d
index 65c354490d1e9952ac0718d076e8546fd80197f5..998a78a0d91f194559c76be1d64fe61205276b95 100644 (file)
 # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
 #============================================================================
 # Move the IP address from eth0 onto the Xen bridge (nbe-br).
-# Works best if the bridge control utils (brctl) have been installed.
+# Only works if the bridge control utils (brctl) have been installed.
 #============================================================================
-import os
-import os.path
-import re
-import sys
 
 from getopt import getopt
+from xenmgr.XendBridge import *
 
-os.defpath = os.defpath+':/sbin:/usr/sbin:/usr/local/sbin'
-CMD_IFCONFIG = 'ifconfig'
-CMD_ROUTE    = 'route'
-CMD_BRCTL    = 'brctl'
-
-def routes():
-    """Return a list of the routes.
-    """
-    fin = os.popen(CMD_ROUTE + ' -n', 'r')
-    routes = []
-    for x in fin:
-        if x.startswith('Kernel'): continue
-        if x.startswith('Destination'): continue
-        x = x.strip()
-        y = x.split()
-        z = { 'destination': y[0],
-              'gateway'    : y[1],
-              'mask'       : y[2],
-              'flags'      : y[3],
-              'metric'     : y[4],
-              'ref'        : y[5],
-              'use'        : y[6],
-              'interface'  : y[7] }
-        routes.append(z)
-    return routes
-
-def cmd(p, s):
-    """Print and execute command 'p' with args 's'.
-    """
-    global opts
-    c = p + ' ' + s
-    if opts.verbose: print c
-    if not opts.dryrun:
-        os.system(c)
-
-def ifconfig(interface):
-    """Return the ip config for an interface,
-    """
-    fin = os.popen(CMD_IFCONFIG + ' %s' % interface, 'r')
-    inetre = re.compile('\s*inet\s*addr:(?P<address>\S*)\s*Bcast:(?P<broadcast>\S*)\s*Mask:(?P<mask>\S*)')
-    info = None
-    for x in fin:
-        m = inetre.match(x)
-        if not m: continue
-        info = m.groupdict()
-        info['interface'] = interface
-        break
-    return info
-
-def reconfigure(interface, bridge):
-    """Reconfigure an interface to be attached to a bridge, and give the bridge
-    the IP address etc. from interface. Move the default route to the interface
-    to the bridge.
-    """
-    intf_info = ifconfig(interface)
-    if not intf_info:
-        print 'Interface not found:', interface
-        return
-    #bridge_info = ifconfig(bridge)
-    #if not bridge_info:
-    #    print 'Bridge not found:', bridge
-    #    return
-    route_info = routes()
-    intf_info['bridge'] = bridge
-    intf_info['gateway'] = None
-    for r in route_info:
-        if (r['destination'] == '0.0.0.0' and
-            'G' in r['flags'] and
-            r['interface'] == interface):
-            intf_info['gateway'] = r['gateway']
-    if not intf_info['gateway']:
-        print 'Gateway not found: ', interface
-        return
-    cmd(CMD_IFCONFIG, '%(bridge)s %(address)s netmask %(mask)s broadcast %(broadcast)s up' % intf_info)
-    cmd(CMD_ROUTE, 'add default gateway %(gateway)s dev %(bridge)s' % intf_info)
-    cmd(CMD_BRCTL, 'addif %(bridge)s %(interface)s' % intf_info)
-    cmd(CMD_IFCONFIG, '%(interface)s 0.0.0.0' % intf_info)
-
-defaults = {
-    'interface': 'eth0',
-    'bridge'   : 'nbe-br',
-    'verbose'  : 1,
-    'dryrun'   : 0,
-    }
-
-short_options = 'hvqni:b:'
-long_options  = ['help', 'verbose', 'quiet', 'interface=', 'bridge=']
+short_options = 'hvqni:b:c'
+long_options  = ['help', 'verbose', 'quiet',
+                 'interface=', 'bridge=', 'create']
 
 def usage():
     print """Usage:
@@ -107,12 +20,13 @@ def usage():
     Reconfigure routing so that <bridge> has the IP address from
     <interface>. This lets IP carry on working when <interface>
     is attached to <bridge> for virtual networking.
-    If brctl is available, <interface> is added to <bridge>,
+    Uses brctl to add <interface> to <bridge>,
     so this can be run before any domains have been created.
     """ % sys.argv[0]
     print """
     -i, --interface <interface>    interface, default %(interface)s.
     -b, --bridge <bridge>          bridge, default %(bridge)s.
+    -c, --create                   create the bridge.
     -v, --verbose                  Print commands.
     -q, --quiet                    Don't print commands.
     -n, --dry-run                  Don't execute commands.
@@ -120,32 +34,28 @@ def usage():
     """ % defaults
     sys.exit(1)
 
-class Opts:
-
-    def __init__(self, defaults):
-        for (k, v) in defaults.items():
-            setattr(self, k, v)
-        pass
 
 def main():
-    global opts
-    opts = Opts(defaults)
+    lopts = set_opts(Opts(defaults))
+    lopts.dryrun = 0
     (options, args) = getopt(sys.argv[1:], short_options, long_options)
     if args: usage()
     for k, v in options:
         if k in ['-h', '--help']:
             usage()
+        elif k in ['-c', '--create']:
+            lopts.create = 1
         elif k in ['-i', '--interface']:
-            opts.interface = v
+            lopts.interface = v
         elif k in ['-b', '--bridge']:
-            opts.bridge = v
+            lopts.bridge = v
         elif k in ['-q', '--quiet']:
-            opts.verbose = 0
+            lopts.verbose = 0
         elif k in ['-v', '--verbose']:
-            opts.verbose = 1
+            lopts.verbose = 1
         elif k in ['-n', '--dry-run']:
-            opts.dryrun = 1
-    reconfigure(opts.interface, opts.bridge)
+            lopts.dryrun = 1
+    reconfigure(lopts.interface, lopts.bridge)
 
 if __name__ == '__main__':
     main()